﻿using System;
using System.Collections.Generic;
using System.Linq;
using Silvermoon.Controls;
using System.Text;

namespace Silvermoon.UI
{
    /// <summary>
    /// Defines and controls states of controls.
    /// </summary>
    public class VisualStateManager
    {
        #region statics

        private static Dictionary<Control, VisualStateManager> customManagers = new Dictionary<Control, VisualStateManager>();
        private static Dictionary<Type, VisualStateManager> classManagers = new Dictionary<Type, VisualStateManager>();

        public static VisualStateManager GetCustomStateManager(Control c)
        {
            VisualStateManager manager;
            if (customManagers.TryGetValue(c, out manager)) return manager;
            return null;
        }

        /// <summary>
        /// Gets a VisualStateManager for the specified control.
        /// </summary>
        /// <param name="c">Control for which to get a VisualStateManager.</param>
        /// <returns>VisualStateManager, otherwise null.</returns>
        public static VisualStateManager GetStateManager(Control c)
        {
            VisualStateManager manager;
            if (customManagers.TryGetValue(c, out manager)) return manager;
            Type type = c.GetType();
            if (classManagers.TryGetValue(type, out manager)) return manager;

            Type parentType = type.BaseType;
            while (parentType != null)
            {
                if (classManagers.TryGetValue(parentType, out manager))
                {
                    // add to dictionary for faster access:
                    VisualStateManager.RegisterClassManager(type, manager);
                    return manager;
                }
                parentType = parentType.BaseType;
            }

            return null;
        }

        public static VisualStateManager GetStateManager(Type type)
        {
            VisualStateManager manager;
            if (classManagers.TryGetValue(type, out manager)) return manager;

            Type parentType = type.BaseType;
            while (parentType != null)
            {
                if (classManagers.TryGetValue(parentType, out manager))
                {
                    // add to dictionary for faster access:
                    VisualStateManager.RegisterClassManager(type, manager);
                    return manager;
                }
                parentType = parentType.BaseType;
            }

            return null;
        }

        /// <summary>
        /// Sets a VisualStateManager for a single control.
        /// </summary>
        /// <param name="c">Control for which to set the VisualStateManager.</param>
        /// <param name="manager">VisualStateManager for that control.</param>
        public static void SetStateManager(Control c, VisualStateManager manager)
        {
            customManagers.Remove(c);
            customManagers.Add(c, manager);
        }

        public static void SetStateManagerIfEmpty(Control c, VisualStateManager manager)
        {
            if (!customManagers.ContainsKey(c)) customManagers.Add(c, manager);
        }



        /// <summary>
        /// Specifies the <see cref="T:VisualStateManager"/> for all controls of the specified type or which are derived from that type.
        /// </summary>
        /// <param name="type">Type of control for which to set the default VisualStateManager.</param>
        /// <param name="manager">VisualStateManager for the specified type and all types derived from.</param>
        public static void RegisterClassManager(Type type, VisualStateManager manager)
        {
            classManagers.Remove(type);
            classManagers.Add(type, manager);
        }

        public static void MergeClassManager(Type type, VisualStateManager manager)
        {
            VisualStateManager current = GetStateManager(type);
            if (current == null)
            {
                RegisterClassManager(type, manager);
            }
            else
            {
                manager.Combine(current);
                RegisterClassManager(type, manager);
            }
        }

        private void Combine(VisualStateManager current)
        {
            int n0 = groups.Length;
            int n1 = current.groups.Length;
            VisualStateGroup[] newGroups = new VisualStateGroup[n0 + n1];
            groups.CopyTo(newGroups, 0);
            current.groups.CopyTo(newGroups, n0);
            groups = newGroups;
        }


        /// <summary>
        /// Sets the default value for the specified elements property if the property is currently changed by a state, otherwise it does only return false.
        /// </summary>
        /// <typeparam name="T">Type of property.</typeparam>
        /// <param name="e">Element that contains the property to set.</param>
        /// <param name="property">Name of the property.</param>
        /// <param name="defaultvalue">default value of the property.</param>
        /// <returns>True if the default value was set for a default value, otherwise false.</returns>
        public static bool SetDefaultValue<T>(object e, string property, T defaultValue)
        {
            throw new NotImplementedException();
            //return StateKey.SetOriginalValue<T>(e, property, defaultValue);
        }

        internal static void RemoveControlStateManager(Control control)
        {
            customManagers.Remove(control);
        }

        #endregion
        #region fields

        private VisualStateGroup[] groups;

        #endregion
        #region ctors

        public VisualStateManager()
            : base()
        {
        }

        public VisualStateManager(params VisualStateGroup[] groups)
            : base()
        {
            this.groups = groups;
        }

        public VisualStateManager(params VisualState[] states)
            : base()
        {
            VisualStateGroup group = new VisualStateGroup(states);
            groups = new VisualStateGroup[] { group };
        }

        #endregion
        #region props

        public VisualStateGroup[] Groups
        {
            get { return groups; }
            set { groups = value; }
        }

        #endregion
        #region Methods

        /// <summary>
        /// Changes the visual appearance of the specified control based on the VisualStates set for that state.
        /// </summary>
        /// <param name="control">Control to change visual state.</param>
        /// <param name="state">State to set.</param>
        /// <param name="useTransition">if set to <c>true</c> appearance changes within a transition, if specified in a VisualState, otherwise directly.</param>
        public static void GoToState(Control control, string state, bool useTransition)
        {
            VisualStateManager manager = control.StateManager;
            if (manager != null)
            {
                manager.GoTo(control, state, useTransition);
            }
        }

        public void GoTo(Control control, string state, bool useTransition)
        {
            //if (StateConverter != null) state = StateConverter(control, state);
            if (Groups != null)
            {
                foreach (VisualStateGroup group in Groups)
                {
                    VisualState visualState = group.GetVisualState(state);
                    if (visualState != null)
                    {
                        group.GoToState(control, state, useTransition);
                    }
                }
            }
        }

        #endregion


        public VisualState GetState(string name)
        {
            if (groups==null) return null;
            foreach(var g in groups)
            {
                var state = g.GetVisualState(name);
                if (state!=null) return state;
            }
            return null;
        }
    }
}
